今天進到 DAY25 我終於在倒數五天把 code 給擠出來了,對於許多訂閱的朋友感到虧欠,在之後幾天甚至鐵人賽結束之後,我都會陸續把前面文章做更新,也會持續在這個系列中把相關的東西做完善,可能會貼到部落格,但也會確保在 ITHome 也會同步更新。
今天的主題,關於初步的測試我會延後再做討論,我會先把 Matlab 的檔案和大家分享,大家可以在 GitHub 中先看到一個基礎檔案,目前還不能跑還請見諒,但是大概的程式碼架構就是這樣,我相信各位一定能用 python 或 R 或其他程式語言實作出更好的程式碼,在這邊僅提供一個原型能跑點簡單的基礎檔案,在個人工作上我們也是有內部一個系統專門做類神經網路的設計,因為我們的輸出結果都要同步接到應用場景的後台,所以為了確保設計出來的模型是能用的,公司規定我們得用一套建立在 MATLAB 上的內部開發的工具箱進行設計。
好,我這次鐵人賽中,最核心的關鍵就是要把啟發式演算法搭配類神經網路實做出來,並且跑幾個例子給大家看看,這邊是RBFNNPSO的 script 型式的程式碼(在Matlab中可以將城市寫成 script 或是 function)以下簡單做個說明:
首先先將所有的要使用到的變數呼叫一次,確定工作空間(workspace)裡面都已經有設定好
input; % 訓練樣本輸入資料
outsampleInput; % 測試樣本輸入資料
label; % 訓練樣本標籤值
outsampleLabel; % 測試樣本標籤值
normalizeMethod; % 標準化方式, 原則上是標準化到 0 至 1
signalType; % 訊號計算方式, 這邊會在後續討論
particleNumber = 10 ; % 粒子群優化法的粒子數
hiddenNeuronNnumber = 30 ; % RBFNN 的中心點個數
thershold = 10^(-8) ; % 訓練過程中的收斂閥值
接著當然是對資料進行標準化啦
% 訓練與測試樣本的輸入資料都進行標準化,採用的是訓練樣本的最大最小值區間
[ normalizeInput, normalizeOutsampleInput, inputMaxmin ] = normalization(input, outsampleInput, normalizeMethod);
% 訓練與測試樣本的標籤值也要標準化,一樣採用的是訓練樣本標籤值的最大最小值區間
[ normalizeLabel, normalizeOutsampleLabel, labelMaxmin ] = normalization(label, outsampleLabel, normalizeMethod);
接著初始化粒子群優化法的參數,這邊就是前面幾天有提到的初始化權重的函數
% centerMatrix : 中心點矩陣,放粒子對應的RBFNN中心點的矩陣
% velocityMatrix : 粒子速度矩陣,放粒子優化對應的速度矩陣
% groupBest : 粒子群最佳解
% particleBest : 粒子個體過往最佳解
% fitnessValue : 配適值, 就是我們要以什麼來做優化
%
[ centerMatrix, velocityMatrix, groupBestCenterMatrix, particleBestCenterMatrix, groupBestFitnessValue, particleBestFitnessValue ] = Initialize( particleNumber, hiddenNeuronNnumber, normalizeInput );
在對一些參數進行宣告
% 放每一個粒子的配適值的變數做宣告
centerFitnessValue = zeros(1, particleNumber);
% 放每一個粒子對應的NAV值的變數做宣告
nNAV = length(normalizeInput(:,1))-1;
centerNetAssetValue = zeros(particleNumber, nNAV );
並建立一組向量記錄每回合群最佳、粒子最佳的的配適值
groupBestFitnessValueLog = zeros(1,maxIteration) ;
averageParticleBestFitnessValueLog = zeros(1,maxIteration);
varianceParticleBestFitnessValueLog = zeros(1,maxIteration);
開始訓練囉
for iteration = 1 : maxIteration
...
根據每個粒子分開做訓練,這邊實務上可能會跑個平行運算,利用 parfor
指令
for iParticle = 1 : particleNumber
...
接著就是標準類神經網路的作業流程
% 從粒子群矩陣取出粒子位置,也就是RBFNN的中心點參數
center = getParticle( centerMatrix, iParticle );
% 根據標準化後的輸入資料與中心點,計算RBF值
[ RBFvalue, ~ ] = RBF ( normalizeInput, center );
% 根據 RBF值與標準化後的標籤值與RBF值計算輸出層權重與預測值
[ weight , prediction ] = LMS( normalizeInput, normalizeLabel, RBFvalue );
然後脫離類神經網路,進到應用場景的作業流程,這邊是模擬金融市場的應用場景,會計算交易訊號並得到淨值曲線,原則上在實際上線的時候,這些資訊應該都是在應用場景的系統中做計算,不會在你的模型訓練系統中計算。
% 根據預測值來計算交易訊號
[ particleSignal ] = signal( normalizeLabel, prediction, signalType, signalParameter );
% 根據交易訊號與交易標的價格資料,計算NAV曲線(淨值曲線)
[ particleNAV, particleDD ] = nav ( target, particleSignal, spread );
% 根據淨值曲線與最大連續虧損,計算本粒子的配適值
fitnessValue = fitness( particleNAV, particleDD );
儲存結果
% 將本次計算放回共同儲存所有粒子資訊的矩陣中
centerMatrix(iParticle,:,:) = center ;
centerNetAssetValue(iParticle,:) = particleNAV ;
centerFitnessValue(iParticle) = fitnessValue ;
end % end of particle
開始使用粒子群搜索,對粒子參數進行優化,還記得我們有討論到參數優化的三種方式嗎?這邊採用吸收牆方式。
% 每個粒子都跑過一次 RBFNN 並計算出配適值之後,就要開始對粒子進行優化
[centerMatrix, velocityMatrix, particleBestCenterMatrix, groupBestCenterMatrix, particleBestFitnessValue, groupBestFitnessValue ] = PSO(...
centerMatrix, velocityMatrix, centerFitnessValue, particleBestCenterMatrix, groupBestCenterMatrix, particleBestFitnessValue, groupBestFitnessValue, iteration, maxIteration );
然後在更新我們的粒子資訊,進到下一個訓練回合
% 根據優化結果,群最佳、粒子最佳的配適值都會被更新,在每回合訓練中都記錄進一組向量
groupBestFitnessValueLog(iteration) = groupBestFitnessValue ;
averageParticleBestFitnessValueLog(iteration) = mean(particleBestFitnessValue);
varianceParticleBestFitnessValueLog(iteration) = var(particleBestFitnessValue);
如果訓練過程中群最佳與粒子最佳的配適值小於一個閥值,則認為粒子群全部收斂並結束訓練,否則就一直訓練直到最大訓練次數
if iteration < maxIteration
if abs(mean(particleBestFitnessValue)-groupBestFitnessValue) < thershold
groupBestFitnessValueLog = groupBestFitnessValueLog(1:iteration);
averageParticleBestFitnessValueLog = averageParticleBestFitnessValueLog(1:iteration);
varianceParticleBestFitnessValueLog = varianceParticleBestFitnessValueLog(1:iteration);
break
end
end
end % end of iteration
訓練結束,將群最佳解的中心點、中心寬度與輸出層權重取出
groupBestCenter = getParticle( groupBestCenterMatrix, 1);
[ groupBestRBFvalue, groupBestWidth ] = RBF( normalizeInput, groupBestCenter );
[ groupBestWeight, groupBestPrediction ] = LMS( normalizeInput, normalizeLabel, groupBestFitnessValue );
% 將群最佳解計算訓練樣本中的訊號與NAV和最大連續虧損Drawdown
[ insampleSIgnal ] = signal( normalizeLabel, groupBestPrediction, signalType, signalParameter );
[ insampleNAV, insampleDrawdown ] = nav ( target, insampleSignal, spread );
% 接著同樣透過測試樣本資料,計算測試樣本的預測值
[ outsamplePrediction ] = outsampleTest( normalizeOutsampleInput, groupBestCenter, groupBestWeight, groupBestWidth );
% 再從測試樣本中計算訊號與NAV和最大連續虧損,這樣我們就知道整個訓練下來是否在測試樣本能用
[ outsampleSignal ] = signal ( normalizeOutsampleLabel, outsamplePrediction, signalType, signalParameter );
[ outsampleNAV, outsampleDrawdown ] = nav ( outsampleTarget, outsampleSignal, spread );
簡單來說就是這樣啦!
大家一定霧煞煞,我會在後續幾天陸續做說明和拿幾筆資料跑給大家,讓大家能明白。